package com.chiaching.framwork.core.feign;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import feign.RequestTemplate;
import feign.codec.EncodeException;
import feign.codec.Encoder;
import org.springframework.beans.BeanUtils;
import org.springframework.http.MediaType;

import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.net.URLEncoder;
import java.util.Collection;
import java.util.Date;

public class DefaultEncoder implements Encoder {

    private static final String CONTENT_TYPE = "Content-Type";

    @Override
    public void encode(Object object, Type bodyType, RequestTemplate template) {
        if (object == null) return;
        Collection<String> collection = template.headers().get(CONTENT_TYPE);
        String body;
        if (collection != null) {
            if (collection.contains(MediaType.APPLICATION_JSON_VALUE)) {
                body = JSON.toJSONString(object, SerializerFeature.WriteEnumUsingToString);
            } else if (collection.contains(MediaType.APPLICATION_FORM_URLENCODED_VALUE)) {
                body = doCreateFormString(object);
            } else {
                throw new EncodeException("unsupported media type!");
            }
        } else {
            throw new EncodeException("need media type!");
        }
        template.body(body);
    }

    private String doCreateFormString(Object object) {
        StringBuilder stringBuilder = new StringBuilder();
        PropertyDescriptor[] propertyDescriptors = BeanUtils.getPropertyDescriptors(object.getClass());
        boolean isFirst = true;
        try {
            for (PropertyDescriptor propertyDescriptor : propertyDescriptors) {
                String propertyName = propertyDescriptor.getName();
                if ("class".equals(propertyName)) continue;
                Method readMethod = propertyDescriptor.getReadMethod();
                if (readMethod != null) {
                    Object value = readMethod.invoke(object);
                    if (value == null) {
                        continue;
                    }
                    if (!isFirst) {
                        stringBuilder.append("&");
                    } else {
                        isFirst = false;
                    }
                    stringBuilder.append(propertyName);
                    stringBuilder.append("=");
                    if (propertyDescriptor.getPropertyType().isAssignableFrom(Date.class)) {
                        stringBuilder.append(((Date) value).getTime());
                    } else {
                        stringBuilder.append(URLEncoder.encode(String.valueOf(value), "utf-8"));
                    }
                }
            }
        } catch (Exception e) {
            throw new EncodeException("form data type serialize fail!", e);
        }
        return stringBuilder.toString();
    }

}